package com.zmzncs.lmtc.controller;

import java.awt.image.ImageFilter;
import java.io.*;
import java.net.URL;
import java.util.*;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectRequest;
import com.zmzncs.lmtc.common.pojo.FileBean;
import com.zmzncs.lmtc.common.pojo.FileBeanOss;
import com.zmzncs.lmtc.common.pojo.Rest;
import com.zmzncs.lmtc.common.pojo.enums.RestCode;
import com.zmzncs.lmtc.common.util.CompressImage;
import com.zmzncs.lmtc.common.util.ExceptionUtil;
import com.zmzncs.lmtc.common.util.RestUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;


@Api(tags = "文件上传")
@RestController("UploadController")
@RequestMapping("/upload")
@Scope("prototype")
@Slf4j
public class UploadController {

    @Autowired
    CompressImage compressImage;

    @Value("${file-path}")
    private String filePath;
    @Value("${file-url-prefix}")
    private String fileUrlPrefix;

    @ApiOperation(value = "多文件上传本地")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "files", value = "文件列表", dataType = "MultipartFile", allowMultiple = true, required = true),
    })
    @PostMapping(value = "/upload-batch", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public Rest batchUpload(@RequestParam(value="files") MultipartFile[] files) {
        if(files.length == 0){
            ExceptionUtil.businessException("文件不能为空");
        }

        List<FileBean> fileBeanList = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            MultipartFile multipartFile = files[i];
            //  文件内容不为空
            if(multipartFile.getSize() > 0){
                //文件后缀名
                String suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().indexOf(".") + 1);
                //文件新名称
                String newFileName = System.currentTimeMillis() + (int) ((Math.random() * 9 + 1) * 100) + "@_@" + multipartFile.getOriginalFilename();
                //中间目录
                String middlePath = DateFormatUtils.format(new Date(), "yyyy-MM-dd") + File.separator;
                //全目录
                String fileFullName = filePath + fileClassification(suffix) + File.separator + middlePath + newFileName;

                //压缩图片并上传
                compressImage.generateFixedSizeImage(multipartFile, fileFullName);

                // 图片访问地址（tomcat服务器）
//            urls[i] = File.separator + fileClassification(suffix) + File.separator + middlePath + newFileName;
                String url = File.separator + fileClassification(suffix) + File.separator + middlePath + newFileName;
                BufferedOutputStream out = null;
                try {
                    File file = new File(fileFullName);
                    if (!file.getParentFile().exists()) {
                        file.getParentFile().mkdirs();
                    }

                    out = new BufferedOutputStream(new FileOutputStream(new File(fileFullName)));
                    out.write(multipartFile.getBytes());
                    out.flush();

                    FileBean fileBean = new FileBean();
                    fileBean.setUrl(fileUrlPrefix + url);    // 访问地址
                    fileBean.setName(multipartFile.getOriginalFilename());
                    fileBeanList.add(fileBean);
                } catch (Exception e) {
                    e.printStackTrace();

                } finally {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        return RestUtil.success(fileBeanList);
    }

    @ApiOperation(value = "分片上传")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", dataType = "MultipartFile", allowMultiple = true, required = true),
            @ApiImplicitParam(name = "fileName", value = "文件名称", required = true),
            @ApiImplicitParam(name = "index", value = "第几个分片", required = true),
            @ApiImplicitParam(name = "total", value = "文件总大小", required = true),
            @ApiImplicitParam(name = "uuid", value = "uuid", required = true),
    })
    @PostMapping("/fragmentation-upload")
    public Rest fragmentationUpload(@RequestParam("file") MultipartFile file, @RequestParam("fileName") String fileName, @RequestParam("index") int index, @RequestParam("total") int total, @RequestParam("uuid") String uuid) {
        String name = fileName.substring(0, fileName.lastIndexOf("."));

        File uploadFile = new File(filePath + "/" + uuid, uuid + name + "-" + index + ".tem");

        if (!uploadFile.getParentFile().exists()) {
            uploadFile.getParentFile().mkdirs();
        }

        //  *********************************写入临时文件
        BufferedOutputStream out = null;
        try {
            out = new BufferedOutputStream(new FileOutputStream(uploadFile));
            out.write(file.getBytes());
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
            return RestUtil.error(RestCode.CODE_502.getCode(), "第" + index + "片段出错");
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        //  *********************************合并临时文件
        try {
            if (index < total) {
                return RestUtil.success(RestCode.CODE_201.getCode(), RestCode.CODE_201.getDesc());
            } else {
                File dirFile = new File(filePath + "/" + uuid);
                if (!dirFile.exists()) {
                    throw new RuntimeException("文件不存在！");
                }
                //分片上传的文件已经位于同一个文件夹下，方便寻找和遍历（当文件数大于十的时候记得排序用冒泡排序确保顺序是正确的）
                String[] fileNames = dirFile.list();
                // 按照文件的索引进行冒泡排序
                for (int i = 0; i < fileNames.length; i++) {
                    for (int j = 0; j < fileNames.length - i - 1; j++) {
                        int varJ = Integer.parseInt(fileNames[j].substring(fileNames[j].lastIndexOf("-") + 1, fileNames[j].lastIndexOf(".")));
                        int varJ1 = Integer.parseInt(fileNames[j + 1].substring(fileNames[j + 1].lastIndexOf("-") + 1, fileNames[j + 1].lastIndexOf(".")));
                        if (varJ > varJ1) { // 即这两个相邻的数是逆序的 交换
                            String temp = fileNames[j];
                            fileNames[j] = fileNames[j + 1];
                            fileNames[j + 1] = temp;
                        }
                    }
                }

                // 创建空的合并文件
                File targetFile = new File(filePath, fileName);
                RandomAccessFile writeFile = new RandomAccessFile(targetFile, "rw");

                int position = 0;
                for (String fileNameF: fileNames) {
                    File sourceFile = new File(filePath + uuid, fileNameF);
                    RandomAccessFile readFile = new RandomAccessFile(sourceFile, "rw");
                    int chunksize = 1024 * 3;
                    byte[] buf = new byte[chunksize];
                    writeFile.seek(position);
                    int byteCount;
                    while ((byteCount = readFile.read(buf)) != -1) {
                        if (byteCount != chunksize) {
                            byte[] tempBytes = new byte[byteCount];
                            System.arraycopy(buf, 0, tempBytes, 0, byteCount);
                            buf = tempBytes;
                        }
                        writeFile.write(buf);
                        position = position + byteCount;
                    }
                    readFile.close();
                    log.info(sourceFile.toString());
                    sourceFile.delete();//删除缓存的临时文件
                }
                writeFile.close();
                dirFile.delete();
                return RestUtil.success();
            }
        } catch (IOException e) {
            e.printStackTrace();
            return RestUtil.error("合并文件出错");
        }
    }

    @ApiOperation(value = "多文件上传阿里oss")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "files", value = "文件列表", dataType = "MultipartFile", allowMultiple = true, required = true),
            @ApiImplicitParam(name = "bucketName", value = "模块名"),
    })
    @PostMapping(value = "/upload-batch-oss")
    public Rest batchUploadOSS(MultipartFile[] files, String bucketName) throws IOException {
        String endpoint = "http://oss-cn-beijing.aliyuncs.com";
        String accessKeyId = "LTAI7RDweCFYN01O";
        String accessKeySecret = "xG0haFDFCuVzPwH9cbO51EwrEWaH82";
        String securityToken = "";
        bucketName = bucketName == null ?  "guanyua" : bucketName;
//        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret, securityToken);
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

        List<FileBeanOss> fileBeanOssList = new ArrayList<>();
        try {
            if (!ossClient.doesBucketExist(bucketName)) {
                return RestUtil.warning(RestCode.CODE_403.getCode(), "您的Bucket不存在");
//                LOG.info("您的Bucket不存在，创建Bucket：" + bucketName + "。");
//                ossClient.createBucket(bucketName);
            }

            for (int i = 0; i < files.length; i++) {
                MultipartFile multipartFile = files[i];
                if(null != multipartFile){
                    //文件后缀名
                    String suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().indexOf(".") + 1);
                    //文件新名称
                    String newFileName = String.valueOf(System.currentTimeMillis() + (int) ((Math.random() * 9 + 1) * 100)) + "@_@" + multipartFile.getOriginalFilename();
                    if(!"".equals(multipartFile.getOriginalFilename().trim())){
                        //*****************************上传到OSS*********************************************
                        //OSS中间目录
                        String OSSMiddlePath = DateFormatUtils.format(new Date(), "yyyyMMdd") + "/";
                        // OSS全目录，key
                        String fileKey = fileClassification(suffix) + "/" + OSSMiddlePath + newFileName;

                        ossClient.putObject(new PutObjectRequest(bucketName, fileKey, new ByteArrayInputStream(multipartFile.getBytes())));

                        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000 * 24 * 365 * 10);  //10年
                        URL url = ossClient.generatePresignedUrl(bucketName, fileKey, expiration);
                        log.info("存入OSS成功，OSS文件地址：" + url.toString());

                        FileBeanOss fileBeanOss = new FileBeanOss();
                        fileBeanOss.setUrl(url.toString());    // oss访问地址
                        fileBeanOss.setName(multipartFile.getOriginalFilename());
                        fileBeanOss.setOssObjectKey(fileKey);
                        fileBeanOssList.add(fileBeanOss);
                    }
                }
            }
        } catch (Exception e) {
            throw e;
        } finally {
            ossClient.shutdown();
        }

        return RestUtil.success(fileBeanOssList);
    }

    /**
     * 文件分类
     */
    private String fileClassification(String suffix){
        String[] imageType = {"jpg", "bmp", "gif", "png"};
        String[] audioType = {"wmv", "mp3", "wma", "mp3pro", "mod", "ra", "md", "asf", "aac", "vqf", "mid", "ogg", "m4a", "aac+", "aiff", "au", "cd", "wav", "flac", "ape"};
        String[] videoType = {"avi", "mov", "rmvb", "flv", "rmvb", "flv", "mp4", "3gp", "mkv"};
        String[] documentType = {"doc", "docx", "vsd", "xls", "xlsx", "ppt", "pptx"};

        if(Arrays.asList(imageType).contains(suffix.toLowerCase())){
            return "image";
        } else if(Arrays.asList(audioType).contains(suffix.toLowerCase())) {
            return "audio";
        } else if(Arrays.asList(videoType).contains(suffix.toLowerCase())) {
            return "video";
        } else if (Arrays.asList(documentType).contains(suffix.toLowerCase())){
            return "document";
        } else {
            return "other";
        }
    }

}